%{
	#include <stdlib.h>
	#include "SyntaxNode.h"
	//used to ignore the -Wimplicit-function-declaration warning shwon at line 1656 by using yyerror
	//#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
	#define YYSTYPE PSyntaxNode
	PSyntaxNode root=NULL; 
	extern LexVal lexval;
	extern int yylineno;
	extern int yylex(void);
	//yyerror function prototype
	int yyerror(const char* s); 
%}

//gets all the regular expressione defined in this file with NODE_ appended as first character sequence
//cat parser.y | sed '/^[^a-z]/d' | cut -d':' -f1 | grep -e '^[a-z]' | sed '/^int /d' | tr 'a-z' 'A-Z' | sed 's/^/NODE_/g'
//gets all the regular expressions to easily create semantic table
//cat parser.y | sed '/^%/d' | sed '/^\/\*/d' | sed '/\/\/..*/d' | sed '/^\s\s*#/d' | sed '/^\s\s*;/d' | sed '/^\s\s*[a-zA-Z]/d' | sed '/^int/d' | sed '/^}/d' | tr -s "\t" " " | sed 's/ {..*}//g' | sed '/^$/d' | tr -s "  " " "

/**syntax token for the reserved word "public"*/
%token TOKEN_PUBLIC 
%token TOKEN_PACKAGE 
%token TOKEN_REQUIRE
%token TOKEN_ID
%token TOKEN_CLASS
%token TOKEN_STATIC
%token TOKEN_ABSTRACT
%token TOKEN_EXTENDS
%token TOKEN_READABLE
%token TOKEN_BY
%token TOKEN_WRITEABLE
%token TOKEN_ALL
%token TOKEN_ONLYME
%token TOKEN_CHILDREN
%token TOKEN_MEMBER
%token TOKEN_OF
%token TOKEN_THIS
%token TOKEN_REFERENCE
%token TOKEN_VALUE
%token TOKEN_ARRAY
%token TOKEN_MINUS_D
%token TOKEN_INT
%token TOKEN_STRING
%token TOKEN_BOOL
%token TOKEN_CHAR
%token TOKEN_VAR
%token TOKEN_CONST
%token TOKEN_FUNCTION
%token TOKEN_VOID
%token TOKEN_REAL
%token TOKEN_COPY
%token TOKEN_WHILE
%token TOKEN_DO
%token TOKEN_FOR
%token TOKEN_TO
%token TOKEN_IF
%token TOKEN_THEN
%token TOKEN_ELSIF
%token TOKEN_ELSE
%token TOKEN_SWITCH
%token TOKEN_CASE
%token TOKEN_DEFAULT
%token TOKEN_CONTINUE
%token TOKEN_BREAK
%token TOKEN_RETURN
%token TOKEN_NEW
%token TOKEN_AND
%token TOKEN_OR
%token TOKEN_LEQ
%token TOKEN_GEQ
%token TOKEN_EQ
%token TOKEN_NE
%token TOKEN_ERROR
%token TOKEN_INTCONST
%token TOKEN_STRINGCONST
%token TOKEN_BOOLCONST
%token TOKEN_CHARCONST
%token TOKEN_FLOATCONST 

%error-verbose


%%

/* --------------------------- program -------------------------------------*/

program							:	group_label_file {$$=$1;}
								|	class_file {$$=$1;}
								;
class_file						:	require_sector class_definition '{' field_declaration_sector method_declaration_sector '}' {root=$$=initNTN(NODE_CLASS_FILE); $$->child=$1; $1->brother=$2; $2->brother=$4; $4->brother=$5;}
								;
group_label_file				:	group_labels_definition_sector {root=$$=initNTN(NODE_GROUP_LABEL_FILE); $$->child=$1;}
								;
								
/*------------------------- label syntax file -------------------------------*/

group_labels_definition_sector	:	group_labels_definition_list {$$=initNTN(NODE_GROUP_LABELS_DEFINITION_SECTOR); $$->child=$1;}
								;
group_labels_definition_list	:	group_labels_definition ';'	group_labels_definition_list {$$=$1; $1->brother=$3;} 
								|	group_labels_definition ';' {$$=$1;}
								;
group_labels_definition			:	modifier_element id_list {$$=initNTN(NODE_GROUP_LABELS_DEFINITION); $$->child=$1; $1->brother=$2;}
								;
id_list							:	TOKEN_ID {$$=initIDNode(lexval);} ',' id_list {$$=$2; $2->brother=$4;}
								|	TOKEN_ID {$$=initIDNode(lexval);}
								;


/*------------------------- modifier possibilities ---------------------------*/

modifier_sector					:	modifier_list {$$=initNTN(NODE_MODIFIER_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_MODIFIER_SECTOR);}
								;
modifier_list					:	modifier_element modifier_list {$$=$1; $1->brother=$2;}
								|	modifier_element {$$=$1;}
								;
modifier_element				:	TOKEN_ABSTRACT {$$=initTerminalNode(NODE_ABSTRACT);}
								|	TOKEN_STATIC {$$=initTerminalNode(NODE_STATIC);}
								|	TOKEN_CONST {$$=initTerminalNode(NODE_CONST);}
								|	TOKEN_REFERENCE TOKEN_OF {$$=initTerminalNode(NODE_REFERENCE);}
								|	TOKEN_VALUE	TOKEN_OF {$$=initTerminalNode(NODE_VALUE);}
								|	TOKEN_PUBLIC {$$=initTerminalNode(NODE_PUBLIC);}
								|	TOKEN_PACKAGE {$$=initTerminalNode(NODE_PACKAGE);}
								|	TOKEN_REAL {$$=initTerminalNode(NODE_REAL);}
								|	TOKEN_COPY {$$=initTerminalNode(NODE_COPY);}
								;

/*--------------------------- read write resource permissions --------------------------------*/

mode_policies_sector			:	read_policies write_policies {$$=initNTN(NODE_MODE_POLICIES_SECTOR); $$->child=$1; $1->brother=$2;}
								|	read_policies {$$=initNTN(NODE_MODE_POLICIES_SECTOR); $$->child=$1; }
								|	write_policies {$$=initNTN(NODE_MODE_POLICIES_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_MODE_POLICIES_SECTOR);}
								;
read_policies					:	TOKEN_READABLE TOKEN_BY access_group_list {$$=initNTN(NODE_READ_POLICIES); $$->child=$3;}
								;
write_policies					:	TOKEN_WRITEABLE TOKEN_BY access_group_list {$$=initNTN(NODE_WRITE_POLICIES); $$->child=$3;}
								;
access_group_list				:	access_group_element ',' access_group_list {$$=$1; $$->brother=$3;}
								|	access_group_element {$$=$1;}
								;
access_group_element			:	TOKEN_ID {$$=initIDNode(lexval);}{$$=initNTN(NODE_ACCESS_GROUP_ELEMENT); $$->child=$2;}
								|	TOKEN_ALL {$$=initNTN(NODE_ACCESS_GROUP_ELEMENT); $$->child=initTerminalNode(NODE_ALL);}
								|	TOKEN_ONLYME {$$=initNTN(NODE_ACCESS_GROUP_ELEMENT); $$->child=initTerminalNode(NODE_ONLYME);}
								|	TOKEN_CHILDREN {$$=initNTN(NODE_ACCESS_GROUP_ELEMENT); $$->child=initTerminalNode(NODE_CHILDREN);}
								;
								
/*----------------------------------- type ---------------------------*/

type							:	simple_type {$$=initNTN(NODE_TYPE); $$->child=$1;}
								|	class_type {$$=initNTN(NODE_TYPE); $$->child=$1;}
								|	array_type {$$=initNTN(NODE_TYPE); $$->child=$1;}
								;
simple_type						:	TOKEN_INT {$$=initNTN(NODE_SIMPLE_TYPE); $$->child=initTerminalNode(NODE_INT_TYPE);}
								|	TOKEN_STRING {$$=initNTN(NODE_SIMPLE_TYPE); $$->child=initTerminalNode(NODE_STRING_TYPE);}
								|	TOKEN_BOOL {$$=initNTN(NODE_SIMPLE_TYPE); $$->child=initTerminalNode(NODE_BOOL_TYPE);}
								|	TOKEN_CHAR {$$=initNTN(NODE_SIMPLE_TYPE); $$->child=initTerminalNode(NODE_CHAR_TYPE);}								
//TODO insert here TOKEN_FLOAT 
								;
class_type						:	TOKEN_ID {$$=initIDNode(lexval);} {$$=initNTN(NODE_CLASS_TYPE); $$->child=$2;}
								;							
array_type						:	TOKEN_INTCONST {$$=initIntConstantNode(lexval);} TOKEN_MINUS_D TOKEN_ARRAY TOKEN_OF type {$$=initNTN(NODE_ARRAY_TYPE); $$->child=$2; $2->brother=$6;}
								;								

/* ------------------------- require sector -------------------------------------*/

require_sector					:	require_list {$$=initNTN(NODE_REQUIRE_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_REQUIRE_SECTOR);}
								;								
require_list					:	require_element require_list {$$=$1; $1->brother=$2;}
								|	require_element {$$=$1;}
								;
require_element					:	TOKEN_REQUIRE TOKEN_ID {$$=initIDNode(lexval);} ';' {$$=initNTN(NODE_REQUIRE_ELEMENT); $$->child=$3;}	
								;
								
/*------------------------- field declaration sector -----------------------------*/

field_declaration_sector		:	field_list {$$=initNTN(NODE_FIELD_DECLARATION_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_FIELD_DECLARATION_SECTOR);}
								;
field_list						:	field_element field_list {$$=$1; $1->brother=$2;}
								|	field_element {$$=$1;}
								;
field_element					:	modifier_sector type TOKEN_ID {$$=initIDNode(lexval);} mode_policies_sector ';' {$$=initNTN(NODE_FIELD_ELEMENT); $$->child=$1; $1->brother=$2; $2->brother=$4; $4->brother=$5;}
								;

/* ------------------------- method declaration sector ---------------------------*/

method_declaration_sector		:	method_list {$$=initNTN(NODE_METHOD_DECLARATION_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_METHOD_DECLARATION_SECTOR);}
								;
method_list						:	method method_list {$$=$1; $1->brother=$2;}
								|	method {$$=$1;}
								;
method							:	TOKEN_FUNCTION modifier_sector return_type TOKEN_ID {$$=initIDNode(lexval);} '(' formal_param_declaration_sector ')' mode_policies_sector '{' stat_sector '}' {$$=initNTN(NODE_METHOD); $$->child=$2; $2->brother=$3; $3->brother=$5; $5->brother=$7; $7->brother=$9; $9->brother=$11;}
								;								
return_type						:	type {$$=initNTN(NODE_RETURN_TYPE); $$->child=$1;}
								|	TOKEN_VOID {$$=initNTN(NODE_RETURN_TYPE); $$->child=NULL;}
								;
formal_param_declaration_sector	:	formal_param_declaration_list {$$=initNTN(NODE_FORMAL_PARAM_DECLARATION_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_FORMAL_PARAM_DECLARATION_SECTOR);}
								;
formal_param_declaration_list	:	formal_param_declaration ',' formal_param_declaration_list {$$=$1; $1->brother=$3;}
								|	formal_param_declaration {$$=$1;}
								;
formal_param_declaration		:	modifier_sector type TOKEN_ID {$$=initIDNode(lexval);} {$$=initNTN(NODE_FORMAL_PARAM_DECLARATION); $$->child=$1; $1->brother=$2; $2->brother=$4;}
								;
								
/* -------------------------- left_hand_side -------------------------*/

left_hand_side					:	TOKEN_THIS {$$=initTerminalNode(NODE_THIS);}
								|	TOKEN_ID {$$=initIDNode(lexval);} {$$=$2;}
								|	field_var {$$=$1;}
								|	array_var {$$=$1;}
								|	procedure_call {$$=$1;}
								;
								//TODO insert SUPER token
								;								
field_var						:	left_hand_side '.' TOKEN_ID {$$=initIDNode(lexval);} {$$=initNTN(NODE_FIELD_VAR); $$->child=$1; $1->brother=$4;}
								;
procedure_call					:	left_hand_side '.' TOKEN_ID {$$=initIDNode(lexval);} '(' actual_param_sector ')' {$$=initNTN(NODE_PROCEDURE_CALL); $$->child=$1; $1->brother=$4; $4->brother=$6;}
								//to match stats like "foobar(5,6);" without "this" declaration
								|	TOKEN_ID {$$=initIDNode(lexval);} '(' actual_param_sector ')' {$$=initNTN(NODE_PROCEDURE_CALL); $$->child=$2; $2->brother=$4;}
								;
actual_param_sector				:	actual_param_list {$$=initNTN(NODE_ACTUAL_PARAM_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_ACTUAL_PARAM_SECTOR);}
								;				
actual_param_list				:	expr ',' actual_param_list {$$=$1; $1->brother=$3;}
								|	expr {$$=$1;}
								;															
array_var						:	left_hand_side '[' expr ']' {$$=initNTN(NODE_ARRAY_VAR); $$->child=$1; $1->brother=$3;}
								;
								
/*----------------------- new instance -----------------------*/

new_instance					:	TOKEN_NEW type {$$=initIDNode(lexval);} instance_mode {$$=initNTN(NODE_NEW_INSTANCE); $$->child=$3; $3->brother=$4;}
								;
instance_mode					:	'(' actual_param_sector ')' {$$=initNTN(NODE_INSTANCE_MODE); $$->child=$2;}
								|	braces_list {$$=initNTN(NODE_INSTANCE_MODE); $$->child=$1;}
								;
braces_list						:	braces_element braces_list {$$=$1; $1->brother=$2;}
								|	braces_element {$$=$1;}
								;
braces_element					:	'[' TOKEN_INTCONST {$$=initIDNode(lexval);} ']' {$$=initNTN(NODE_BRACES_ELEMENT); $$->child=$3;}
								;
								
/*----------------------- expr -------------------------------*/

//interface to external BNF
expr							:	compare_expr {$$=initNTN(NODE_EXPR); $$->child=$1;}
								;
								//used inside expr syntax tree computation 
inner_expr						:	compare_expr {$$=$1;}
								;					
compare_expr					:	logic_expr compare_operator logic_expr {$$=$2; $$->child=$1; $1->brother=$3;}
								|	logic_expr {$$=$1;}
								;
compare_operator				:	'>' {$$=initTerminalNode(NODE_GT);}
								|	'<' {$$=initTerminalNode(NODE_LT);}
								|	TOKEN_GEQ {$$=initTerminalNode(NODE_GEQ);}
								|	TOKEN_LEQ {$$=initTerminalNode(NODE_LEQ);}
								|	TOKEN_EQ {$$=initTerminalNode(NODE_EQ);}
								|	TOKEN_NE {$$=initTerminalNode(NODE_NE);}
								;	
logic_expr						:	logic_expr logic_operator math_expr_1 {$$=$2; $$->child=$1; $1->brother=$3;}
								|	math_expr_1 {$$=$1;}
								;
logic_operator					:	TOKEN_AND {$$=initTerminalNode(NODE_AND);}
								|	TOKEN_OR {$$=initTerminalNode(NODE_OR);}
								;	
math_expr_1						:	math_expr_1 '+' math_expr_2 {$$=initNTN(NODE_PLUS); $$->child=$1; $1->brother=$3;}
								|	math_expr_1 '-' math_expr_2 {$$=initNTN(NODE_MINUS); $$->child=$1; $1->brother=$3;}
								|	math_expr_2 {$$=$1;}
								;	
math_expr_2						:	math_expr_2 '*' term_expr {$$=initNTN(NODE_TIMES); $$->child=$1; $1->brother=$3;}
								|	math_expr_2 '/' term_expr {$$=initNTN(NODE_DIVISION); $$->child=$1; $1->brother=$3;}
								|	math_expr_2 '%' term_expr {$$=initNTN(NODE_REMAINDER); $$->child=$1; $1->brother=$3;}
								|	term_expr {$$=$1;}
								;
term_expr						:	left_hand_side {$$=$1;}
								|	'-' term_expr {$$=initNTN(NODE_OPPOSITE); $$->child=$1;}//-3 is OPPOSITE of 3
								|	'+' term_expr {$$=$1;} //+3 is 3
								|	'!' term_expr {$$=initNTN(NODE_NEGATIVE); $$->child=$1;}
								|	constant {$$=$1;}
								|	new_instance {$$=$1;}
								|	'(' inner_expr ')' {$$=$2;}
								;
constant						:	TOKEN_INTCONST {$$=initIntConstantNode(lexval);} {$$=$2;}
								|	TOKEN_STRINGCONST {$$=initStringConstantNode(lexval);} {$$=$2;}
								|	TOKEN_BOOLCONST {$$=initBoolConstantNode(lexval);} {$$=$2;}
								|	TOKEN_CHARCONST {$$=initCharConstantNode(lexval);} {$$=$2;}
								//TODO insert the float constant
								;
															
/*------------------------- class definition -----------------------------------*/

class_definition				:	TOKEN_CLASS modifier_sector TOKEN_ID {$$=initIDNode(lexval);} additional_clauses_sector {$$=initNTN(NODE_CLASS_DEFINITION); $$->child=$2; $2->brother=$4; $4->brother=$5;}
								;
additional_clauses_sector		:	additional_clause_list {$$=initNTN(NODE_ADDITIONAL_CLAUSES_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_ADDITIONAL_CLAUSES_SECTOR);}
								;
additional_clause_list			:	additional_clause additional_clause_list {$$=$1; $1->brother=$2;}
								|	additional_clause {$$=$1;}
								;
additional_clause				:	extends_clause {$$=initNTN(NODE_ADDITIONAL_CLAUSE); $$->child=$1;}
								|	group_member_clause {$$=initNTN(NODE_ADDITIONAL_CLAUSE); $$->child=$1;}
								;
extends_clause					:	TOKEN_EXTENDS id_list {$$=initNTN(NODE_EXTENDS_CLAUSE); $$->child=$2;}
								;
group_member_clause				:	TOKEN_MEMBER TOKEN_OF id_list {$$=initNTN(NODE_GROUP_MEMBER_CLAUSE); $$->child=$3;}
								;															

/*-------------------------- method body --------------------------*/														

stat_sector						:	stat_list {$$=initNTN(NODE_STAT_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_STAT_SECTOR);}
								;
stat_list						:	stat stat_list {$$=$1; $1->brother=$2;}
								|	stat {$$=$1;}
								;
//TODO here you might be able to compress the syntax tree a little								
stat							:	procedure_call ';' {$$=$1;}
								|	local_variable ';' {$$=$1;}
								|	assign_stat ';' {$$=$1;}
								|	while_stat {$$=$1;}
								|	do_while_stat ';' {$$=$1;}
								|	for_stat {$$=$1;}
								|	if_stat {$$=$1;}
								|	switch_stat {$$=$1;}
								|	continue_stat ';' {$$=$1;}
								|	break_stat ';' {$$=$1;}
								|	return_stat ';' {$$=$1;}
								;								
local_variable					:	TOKEN_VAR type TOKEN_ID {$$=initIDNode(lexval);} {$$=initNTN(NODE_LOCAL_VARIABLE); $$->child=$2; $2->brother=$4;}
								;
assign_stat						:	left_hand_side '=' expr {$$=initNTN(NODE_ASSIGN_STAT); $$->child=$1; $1->brother=$3;}
								;
while_stat						:	TOKEN_WHILE '(' expr ')' TOKEN_DO '{' stat_sector '}' {$$=initNTN(NODE_WHILE_STAT); $$->child=$3; $3->brother=$7;}
								;
								//do... while stat can be derived from while do start
do_while_stat					:	TOKEN_DO '{' stat_sector '}' TOKEN_WHILE '(' expr ')' {$$=initNTN(NODE_DO_WHILE_STAT); $$->child=$7; $7->brother=$3;}
								;
for_stat						:	TOKEN_FOR assign_stat TOKEN_TO expr TOKEN_DO '{' stat_sector '}' {$$=initNTN(NODE_FOR_STAT); $$->child=$2; $2->brother=$4; $4->brother=$7;}
								;														
if_stat							:	TOKEN_IF '(' expr ')' TOKEN_THEN '{' stat_sector '}' elsif_else_stat_sector {$$=initNTN(NODE_IF_STAT); $$->child=$3; $3->brother=$7; $7->brother=$9;}
								;
elsif_else_stat_sector			:	elsif_else_stat_list {$$=initNTN(NODE_ELSIF_ELSE_STAT_SECTOR); $$->child=$1;}
								|	{$$=initNTN(NODE_ELSIF_ELSE_STAT_SECTOR);}
								;
								//here we have to link the THEN stat to the ELSE stat of the IF_STAT
elsif_else_stat_list			:	elsif_stat elsif_else_stat_list {$$=$1; $1->child->child->brother->brother=$2;}
								|	elsif_stat {$$=$1;}
								|	else_stat {$$=$1;}
								;
								//the elsif stat is just an if inside an else condition.
elsif_stat						:	TOKEN_ELSIF '(' expr ')' TOKEN_THEN '{' stat_sector '}' {$$=initNTN(NODE_ELSE_STAT); $$->child=initNTN(NODE_IF_STAT); $$->child->child=$3; $3->brother=$7;}
								;
else_stat						:	TOKEN_ELSE '{' stat_sector default_clause '}' {$$=initNTN(NODE_ELSE_STAT); $$->child=$3;}
								;
								//switch stat can be derivaed from do ... while and if ... then ... stat
switch_stat						:	TOKEN_SWITCH '(' expr ')' '{' switch_list  default_clause '}' {$$=initNTN(NODE_SWITCH_STAT); $$->child=$3; $3->brother=$6; $6->brother=$7;}
								;
								//TODO rename in case_clause_sector
switch_list						:	case_clause_list {$$=initNTN(NODE_SWITCH_LIST); $$->child=$1;}
								;
case_clause_list				:	case_clause case_clause_list {$$=$1; $1->brother=$2;}
								|	case_clause {$$=$1;}
								;
case_clause						:	TOKEN_CASE expr ':' '{' stat_sector '}' {$$=initNTN(NODE_CASE_CLAUSE); $$->child=$2; $2->brother=$5;} 
								;
default_clause					:	TOKEN_DEFAULT ':' '{' stat_sector '}' {$$=initNTN(NODE_DEFAULT_CLAUSE); $$->child=$4;}
								|	{$$=initNTN(NODE_DEFAULT_CLAUSE);}
								;
continue_stat					:	TOKEN_CONTINUE {$$=initTerminalNode(NODE_CONTINUE);}
								;
break_stat						:	TOKEN_BREAK {$$=initTerminalNode(NODE_BREAK);}
								;
return_stat						:	TOKEN_RETURN expr {$$=initNTN(NODE_RETURN_STAT); $$->child=$2;}
								;								
%%

int yyerror(const char* s){
	fprintf(stderr,"At line %d: %s (value stored: %s)\n",yylineno,s,lexval.sval);
	return 1;
}
